/* uart.c */

#include <avr/io.h>
#include <stdlib.h>

#include "usart.h"
#include "eeprom.h"

void usart_init(unsigned int ubrr) 
{ 
   /* Set baud rate */ 
   UBRR0H = (unsigned char)(ubrr>>8); 
   UBRR0L = (unsigned char)ubrr; 
   
   /* Enable receiver and transmitter */ 
   UCSR0B = (1<<RXEN0)|(1<<TXEN0); 
   
   /* Set frame format: 8data, 2stop bit */ 
   UCSR0C = (1<<USBS0)|(3<<UCSZ00); 
}

unsigned char usart_rx(void)
{ 
   /* Wait for data to be received */ 
   while ( !(UCSR0A & (1<<RXC0)) )  {
   }
   
   /* Get and return received data from buffer */
   return UDR0; 
}

void usart_tx(unsigned char data)
{ 
   /* Wait for empty transmit buffer */ 
   while ( !( UCSR0A & (1<<UDRE0)) ) {
   }
   
   /* Put data into buffer, sends the data */ 
   UDR0 = data; 
}

void usart_tx_byte(unsigned char n)
{
   char digit;

   if (n >= 100) {
      digit = '0';
      while (n >= 100) {
         n = n - 100;
         digit++;
      }
      usart_tx(digit);
      if (n == 0) {
         usart_tx_string("00");
         return;
      } else if (n < 10) {
         usart_tx('0');
      }
   }

   if (n >= 10) {
      digit = '0';
      while (n >= 10) {
         n = n - 10;
         digit++;
      }
      usart_tx(digit);
      if (n == 0) {
         usart_tx('0');
         return;
      }
   }

   digit = '0' + n;
   usart_tx(digit);
}

void usart_tx_sbyte(char n)
{
   char digit;

   if (n < 0) {
      usart_tx('-');
      n = abs(n);
   }

   if (n >= 100) {
      digit = '0';
      while (n >= 100) {
         n = n - 100;
         digit++;
      }
      usart_tx(digit);
      if (n == 0) {
         usart_tx_string("00");
         return;
      } else if (n < 10) {
         usart_tx('0');
      }
   }

   if (n >= 10) {
      digit = '0';
      while (n >= 10) {
         n = n - 10;
         digit++;
      }
      usart_tx(digit);
      if (n == 0) {
         usart_tx('0');
         return;
      }
   }

   digit = '0' + n;
   usart_tx(digit);
}

void usart_tx_string(char const* s)
{
   while (*s) {
      usart_tx(*s++);
   }
}

void usart_tx_hex(unsigned char c)
{
   static char digits[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
   usart_tx(digits[(c >> 4) & 0x0f]);
   usart_tx(digits[(c >> 0) & 0x0f]);
}

void usart_tx_hexdump(unsigned char* data, unsigned short length)
{
   char ascii[9];
   
   ascii[8] = 0x00;

   unsigned char n = 0;
   
   for (unsigned short offset = 0; offset < length; offset++)
   {      
      if (n == 0) {
         usart_tx_hex((offset >> 8) & 0x00ff);
         usart_tx_hex((offset >> 0) & 0x00ff);
         usart_tx(' ');
         usart_tx(' ');
      }

      if (*data >= 32 && *data <= 126) {
         ascii[n] = *data;
      } else {
         ascii[n] = '.';
      }
      usart_tx_hex(*data++);
      usart_tx(' ');
      n++;
      if (n == 8) {
         usart_tx(' ');
         usart_tx('|');
         usart_tx_string(ascii);
         usart_tx('|');
         usart_tx('\n');
         n = 0;
      }
   }
   
   if (n != 0) {
      while (n != 8) {
         ascii[n] = ' ';
         usart_tx(' ');
         usart_tx(' ');
         usart_tx(' ');
         n++;
      }
      usart_tx(' ');
      usart_tx('|');
      usart_tx_string(ascii);
      usart_tx('|');
      usart_tx('\n');
   }
}
